/*
 * 'tty.h' defines some structures used by tty_io.c and some defines.
 *
 * NOTE! Don't touch this without checking that nothing in rs_io.s or
 * con_io.s breaks. Some constants are hardwired into the system (mainly
 * offsets into 'tty_queue'
 */

#ifndef _TTY_H
#define _TTY_H

#include <termios.h>

#define TTY_BUF_SIZE 1024  // tty 缓冲区（缓冲队列buf）大小

// tty字符缓冲队列数据结构。用于 tty_struct 结构中的读、写和辅助（规范）缓冲队列。
// 图 10-14 tty 字符缓冲队列的操作方式
struct tty_queue {
	unsigned long data;  // 队列缓冲区中含有字符行数值（不是当前字符数）。对于串口终端，则存放串行端口基地址（UART控制器中的第0个port的地址）。
	unsigned long head;  // buf数组中的数据头的索引值
	unsigned long tail;  // buf数组中的数据尾的索引值
	struct task_struct * proc_list;   // 等待进程列表
	char buf[TTY_BUF_SIZE];  // 队列缓冲区
};

// 缓冲区指针a前移1字节，若已超出缓冲区右侧，则指针循环。
#define INC(a) ((a) = ((a)+1) & (TTY_BUF_SIZE-1))
// 缓冲区指针a后退1字节，并循环。
#define DEC(a) ((a) = ((a)-1) & (TTY_BUF_SIZE-1))
// 清空指定队列的缓冲区
#define EMPTY(a) ((a).head == (a).tail)
// 缓冲区还可存放字符的长度（空闲区长度）
#define LEFT(a) (((a).tail-(a).head-1)&(TTY_BUF_SIZE-1))
#define LAST(a) ((a).buf[(TTY_BUF_SIZE-1)&((a).head-1)])
#define FULL(a) (!LEFT(a))
// 缓冲区中己存放字符的长度
#define CHARS(a) (((a).head-(a).tail)&(TTY_BUF_SIZE-1))
// 从 queue 队列项缓冲区中取一字符复制给变量c（从 tail 处，并且 tail+=1)
#define GETCH(queue,c) \
(void)({c=(queue).buf[(queue).tail];INC((queue).tail);})
// （put char）往queue 队列项缓冲区中放置一字符（在head 处，并且head +=1)
#define PUTCH(c,queue) \
(void)({(queue).buf[(queue).head]=(c);INC((queue).head);})

// 判断终端键盘字符类型
#define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR])     // 中断符。发中断信号 SIGINT
#define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT])     // 退出符。发退出信号 SIGQUIT
#define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE])   // 削除符。擦除一个字符
#define KILL_CHAR(tty) ((tty)->termios.c_cc[VKILL])     // 删除行。删除一行字符
#define EOF_CHAR(tty) ((tty)->termios.c_cc[VEOF])       // 文件结束符
#define START_CHAR(tty) ((tty)->termios.c_cc[VSTART])   // 开始符。恢复输出
#define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP])     // 停止符。停止输出
#define SUSPEND_CHAR(tty) ((tty)->termios.c_cc[VSUSP])  // 挂起符。发挂起信号 SIGTSTP

// 终端结构体
struct tty_struct {
	struct termios termios;                   // 终端 io 属性和控制字符数据结构
	int pgrp;                                 // 所属进程组（前台进程组）
	int stopped;                              // 停止标志（是否停止tty输出）
	void (*write)(struct tty_struct * tty);   // tty 写函数指针
	struct tty_queue read_q;                  // tty 读队列
	struct tty_queue write_q;                 // tty 写队列
	struct tty_queue secondary;               // tty 辅助队列(存放规范模式字符序列)， 可称为规范(熟）模式队列。
	};

extern struct tty_struct tty_table[];

/*	intr=^C		quit=^|		erase=del	kill=^U
	eof=^D		vtime=\0	vmin=\1		sxtc=\0
	start=^Q	stop=^S		susp=^Z		eol=\0
	reprint=^R	discard=^U	werase=^W	lnext=^V
	eol2=\0
*/
#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"

void rs_init(void);
void con_init(void);
void tty_init(void);

int tty_read(unsigned c, char * buf, int n);
int tty_write(unsigned c, char * buf, int n);

void rs_write(struct tty_struct * tty);
void con_write(struct tty_struct * tty);

void copy_to_cooked(struct tty_struct * tty);

#endif
